;; Mode: LISP; Syntax: Common-lisp; Package: aklemme
;; Names: Ardell Klemme, Bruce Ho, Jimmy Cumming         Date: 11/05/12
;; Course: ICS 313   Assignment: 6
;; File: macros.lisp

;;;==========================Macros===============================;;;

; AK: macro for new objects, need to push to *objects* and
;     to the *object-location*
(defmacro new-object (name location)
  `(progn
     (cond
       ((and
          (not (our-member-obj ',name *objects*))
          (our-member ',location *nodes*))
        (pushnew ',name *objects*)
        (pushnew '(,name ,location) *object-locations*))
        ((eq location ()) 
          `("Missing location."))
       (t "Object already exists."))))

; AK: Main macro for the new locations in game. We need to push a
;     new node with name and description.
(defmacro new-location (name &body body)
  `(cond
   ((not (our-member ',name *nodes*))
    (progn
      (pushnew '(,name (,@body)) *nodes*)
      (pushnew '(,name ) *edges*)
    ))
   (t "Location already exists.")))

; AK: This is the main macro for setting up new actions in game.
;     Basically, the parameters are straight forward and this makes it
;     easy to add new actions/commands to the game.
(defmacro game-action (command subj obj place &body body)
  `(progn (defun ,command (subject object)
            (if (and (eq *location* ',place)
                     (eq subject ',subj)
                     (eq object ',obj)
                     (have ',subj))
                ,@body
              '(i cant ,command like that.)))
          (pushnew ',command *allowed-commands*)))

; AK: New implementation of new-path macro
;     We only need the following args:
;     origin, destination, direction, path
;     Optional arg: direction-back
(defmacro new-path (origin destination direction path &optional (direction-back "unable"))
  `(cond
    ((or
      ; case 1:origin doesn't exist
      (not (our-member ',origin *nodes*))
      ; case 2:destination doesn't exist                                        
      (not (our-member ',destination *nodes*)))
     ()"Missing location, cannot create path.")
     ; case 3:okay to implement                                                
    (t (progn
        (if (equal ',direction-back "unable")
            nil
          ;now we need to test to see if the destination is already there      
          (cond
           ((our-member ',destination *edges*)
            (pushnew '(,origin ,direction-back ,path)
                 (cdr (assoc ',destination *edges*))))
           (t (pushnew '(,destination
                          (,origin ,direction-back ,path)) *edges*))))
          ; add new location/direction/path to origin's list of edges          
        (pushnew '(,destination ,direction ,path)
                 (cdr (assoc ',origin *edges*)))))))
                 
; AK: Need to move the our-member functions here so that they're defined when we need them.
;JC This is a function from Dr. Reed's samples
(defun our-member (obj lst)
  (if (null lst)
      nil
      (if (eql (caar lst) obj)
          t
          (our-member obj (cdr lst)))))


;JC This is a function from Dr. Reed's samples
;modified for objects
(defun our-member-obj (obj lst)
  (if (null lst)
      nil
      (if (eql (car lst) obj)
          t
          (our-member-obj obj (cdr lst)))))